﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CoreEx.Common.Extensions;
using CoreEx.Common.Repository;
using LinFu.AOP.Interfaces;
using CoreEx.DynamicInvoker;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using System.Collections;

namespace CoreEx.Wcf.Client.Implementation
{
    public class ServiceContractInterceptor : IInterceptor,IInitialize
    {
        private readonly object _actualTarget;
        private IServiceContainer _serviceContainer;
        private IStateTrackerRepository _stateTrackerRepository;

        public ServiceContractInterceptor(object actualTarget)
        {
            _actualTarget = actualTarget;
        }


        public object Intercept(IInvocationInfo info)
        {
            object returnValue = _actualTarget.GetType().DynamicInvoke(_actualTarget, info.TargetMethod.Name, info.Arguments);

            if (ShouldTrackChanges(info))
            {
                var stateTracker = _stateTrackerRepository.GetStateTracker(this);
                RegisterTrackingTargets(returnValue,stateTracker);
            }
            return returnValue;
        }

        protected virtual bool ShouldTrackChanges(IInvocationInfo info)
        {
            var returnType = info.ReturnType.GetGenericElementType();
            if (info.ReturnType.IsEnumerable() && !returnType.IsSystemType())
                return true;
            if (!info.ReturnType.IsEnumerable() && !returnType.IsSystemType())
                return true;
            return false;
        }


        protected void RegisterTrackingTargets(object returnValue, IStateTracker stateTracker)
        {
            if (returnValue.GetType().IsEnumerable())
            {
                var collection = ((IEnumerable) returnValue);
                foreach (var target in collection)
                {
                    stateTracker.Register(target);
                }
            }
            else
                stateTracker.Register(returnValue);
        }

        public void Initialize(IServiceContainer source)
        {
            _stateTrackerRepository = source.GetService<IStateTrackerRepository>();
            _serviceContainer = source;
        }
    }
}
